Skip to main content

HAPI FHIR

HAPI FHIR is the open-source Java implementation of HL7 FHIR. It is the most widely used FHIR toolkit, and for many teams "standing up a FHIR server" means deploying the HAPI JPA server.

It is really three things: a client library, a server framework, and a validation/terminology toolkit.


The client​

Typed access to any FHIR server:

FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://example.org/fhir");

Bundle results = client.search()
.forResource(Patient.class)
.where(Patient.FAMILY.matches().value("Devkota"))
.returnBundle(Bundle.class)
.execute();

A FhirContext is expensive to create and thread-safe to reuse — create one per FHIR version, at startup, and keep it.


The JPA server​

A complete FHIR server persisted to a relational database (PostgreSQL is the usual production choice). It provides:

  • Full CRUD, history and versioning
  • Standard and custom search parameters
  • Transaction and batch bundles
  • Profile validation
  • Terminology services, including loading external code systems
  • Subscriptions
  • Interceptor hooks for authorisation, auditing and business rules

It ships as a deployable application (hapi-fhir-jpaserver-starter) and as libraries to embed in your own Spring application when you need control over security and workflow.


Validation​

Validation is where HAPI earns its place: resources can be checked against the base specification, against implementation-guide profiles, and against terminology bindings.

FhirValidator validator = ctx.newValidator();
validator.registerValidatorModule(new FhirInstanceValidator(ctx));
ValidationResult result = validator.validateWithResult(patient);

Validating at the boundary — rejecting bad data on write — is far cheaper than discovering malformed resources during analysis months later.


Operational notes​

  • Database sizing and indexing dominate performance. Search parameter indexes grow quickly; index only the parameters you actually search on.
  • Turn off unused search parameters to reduce write cost.
  • Authorisation is yours to implement. The AuthorizationInterceptor gives you the hooks; the policy is a design decision. A HAPI server exposed without it is an open patient database.
  • Version per deployment. A FhirContext targets one FHIR release; running two releases side by side (as in a version upgrade) means two deployments, which is exactly how a parallel upgrade environment is built.
  • Cache terminology expansions; naive $expand calls against large value sets are slow.


References​